package com.tidu.utils;

import java.sql.*;
import java.util.*;
import java.util.regex.Pattern;

/**
 * 智能推断表的主键和搜索列（支持多种数据库）
 */
public class TableSchemaAnalyzer {

    // 常见ID列名称模式
    private static final Set<String> ID_PATTERNS = new HashSet<String>() {{
        add("id");
        add("%_id");
        add("%_pk");
        add("%_key");
    }};

    // 常见排除列名称模式
    private static final Set<String> EXCLUDE_COL_PATTERNS = new HashSet<String>() {{
        add("create%");
        add("update%");
        add("delete%");
        add("modify%");
        add("%_time");
        add("%_date");
        add("%_timestamp");
        add("%_at");
        add("version");
        add("password"); // 特别排除密码字段
    }};

    // 常见文本列名称模式
    private static final Set<String> TEXT_COL_PATTERNS = new HashSet<String>() {{
        add("name");
        add("title");
        add("description");
        add("content");
        add("detail");
        add("remark");
        add("comment");
        add("%_txt");
        add("%_text");
        add("%_info");
        add("%_name");
        add("source%");
        add("desc%");
    }};

    /**
     * 获取表的搜索列列表（支持多种数据库）
     *
     * @param conn 数据库连接
     * @param tableName 表名
     * @param dbType 数据库类型 (mysql, oracle, postgresql, sqlserver)
     * @return 搜索列集合
     */
    public static Set<String> getSearchColumns(Connection conn, String tableName, String dbType) throws SQLException {
        Set<String> searchColumns = new HashSet<>();
        DatabaseMetaData metaData = conn.getMetaData();

        // 根据数据库类型处理表名和schema
        String schema = null;
        String processedTableName = tableName;

        // 处理带schema的表名
        if (tableName.contains(".")) {
            String[] parts = tableName.split("\\.");
            if (parts.length == 2) {
                schema = parts[0];
                processedTableName = parts[1];
            }
        }

        // 根据数据库类型调整表名大小写
        processedTableName = formatTableName(processedTableName, dbType);
        if (schema != null) {
            schema = formatSchema(schema, dbType);
        }

        // 获取所有列
        try (ResultSet columns = metaData.getColumns(null, schema, processedTableName, null)) {
            while (columns.next()) {
                String colName = columns.getString("COLUMN_NAME");
                int dataType = columns.getInt("DATA_TYPE");
                String typeName = columns.getString("TYPE_NAME");

                // 排除非文本列和特定列
                if (!isSearchableColumn(colName, dataType, typeName, dbType)) {
                    continue;
                }

                searchColumns.add(colName);
            }
        }

        // 如果没有找到合适的列，则包含所有文本类型列
        if (searchColumns.isEmpty()) {
            try (ResultSet columns = metaData.getColumns(null, schema, processedTableName, null)) {
                while (columns.next()) {
                    int dataType = columns.getInt("DATA_TYPE");
                    String typeName = columns.getString("TYPE_NAME");
                    if (isTextType(dataType, typeName, dbType)) {
                        searchColumns.add(columns.getString("COLUMN_NAME"));
                    }
                }
            }
        }

        return searchColumns;
    }

    /**
     * 获取表的主键列名（支持多种数据库）
     *
     * @param conn 数据库连接
     * @param tableName 表名
     * @param dbType 数据库类型 (mysql, oracle, postgresql, sqlserver)
     * @return 主键列名
     */
    public static String getPrimaryKeyColumn(Connection conn, String tableName, String dbType) throws SQLException {
        DatabaseMetaData metaData = conn.getMetaData();
        String schema = null;
        String processedTableName = tableName;

        // 处理带schema的表名
        if (tableName.contains(".")) {
            String[] parts = tableName.split("\\.");
            if (parts.length == 2) {
                schema = parts[0];
                processedTableName = parts[1];
            }
        }

        // 根据数据库类型调整表名大小写
        processedTableName = formatTableName(processedTableName, dbType);
        if (schema != null) {
            schema = formatSchema(schema, dbType);
        }

        // 尝试获取主键
        try (ResultSet pkRs = metaData.getPrimaryKeys(null, schema, processedTableName)) {
            if (pkRs.next()) {
                return pkRs.getString("COLUMN_NAME");
            }
        }

        // 如果无法获取主键，尝试智能推断
        try (ResultSet columns = metaData.getColumns(null, schema, processedTableName, null)) {
            while (columns.next()) {
                String colName = columns.getString("COLUMN_NAME").toLowerCase();
                for (String pattern : ID_PATTERNS) {
                    if (matchesPattern(colName, pattern)) {
                        return columns.getString("COLUMN_NAME");
                    }
                }
            }
        }

        // 最后尝试使用"id"
        return "id";
    }

    /**
     * 根据数据库类型格式化表名
     */
    private static String formatTableName(String tableName, String dbType) {
        if (tableName == null) return null;

        switch (dbType.toLowerCase()) {
            case "oracle":
                return tableName.toUpperCase();
            case "postgresql":
                return tableName.toLowerCase();
            default:
                return tableName;
        }
    }

    /**
     * 根据数据库类型格式化schema
     */
    private static String formatSchema(String schema, String dbType) {
        if (schema == null) return null;

        switch (dbType.toLowerCase()) {
            case "oracle":
                return schema.toUpperCase();
            case "postgresql":
                return schema.toLowerCase();
            default:
                return schema;
        }
    }

    /**
     * 判断列是否可搜索
     */
    private static boolean isSearchableColumn(String colName, int dataType, String typeName, String dbType) {
        String lowerColName = colName.toLowerCase();

        // 排除ID列和特定列
        for (String pattern : EXCLUDE_COL_PATTERNS) {
            if (matchesPattern(lowerColName, pattern)) {
                return false;
            }
        }

        // 包含文本类型或特定名称模式的列
        return isTextType(dataType, typeName, dbType) ||
                TEXT_COL_PATTERNS.stream().anyMatch(pattern -> matchesPattern(lowerColName, pattern));
    }

    /**
     * 判断是否为文本类型（支持多种数据库）
     */
    private static boolean isTextType(int dataType, String typeName, String dbType) {
        // 转换typeName为小写便于比较
        String lowerTypeName = typeName != null ? typeName.toLowerCase() : "";

        // 标准SQL文本类型
        if (dataType == Types.CHAR ||
                dataType == Types.VARCHAR ||
                dataType == Types.LONGVARCHAR ||
                dataType == Types.CLOB ||
                dataType == Types.NCHAR ||
                dataType == Types.NVARCHAR ||
                dataType == Types.LONGNVARCHAR ||
                dataType == Types.NCLOB ||
                dataType == Types.SQLXML) {
            return true;
        }

        // 数据库特定的文本类型
        switch (dbType.toLowerCase()) {
            case "mysql":
                return lowerTypeName.contains("text") ||
                        lowerTypeName.contains("char") ||
                        lowerTypeName.contains("varchar") ||
                        lowerTypeName.contains("json") ||
                        lowerTypeName.contains("enum") ||
                        lowerTypeName.contains("set");

            case "oracle":
                return lowerTypeName.contains("char") ||
                        lowerTypeName.contains("clob") ||
                        lowerTypeName.contains("nclob") ||
                        lowerTypeName.contains("varchar") ||
                        lowerTypeName.contains("varchar2") ||
                        lowerTypeName.contains("nvarchar") ||
                        lowerTypeName.contains("nvarchar2") ||
                        lowerTypeName.contains("xmltype");

            case "postgresql":
                return lowerTypeName.contains("char") ||
                        lowerTypeName.contains("text") ||
                        lowerTypeName.contains("varchar") ||
                        lowerTypeName.contains("json") ||
                        lowerTypeName.contains("jsonb") ||
                        lowerTypeName.contains("xml") ||
                        lowerTypeName.contains("uuid");

            case "sqlserver":
                return lowerTypeName.contains("char") ||
                        lowerTypeName.contains("text") ||
                        lowerTypeName.contains("varchar") ||
                        lowerTypeName.contains("nchar") ||
                        lowerTypeName.contains("ntext") ||
                        lowerTypeName.contains("nvarchar") ||
                        lowerTypeName.contains("xml");

            default:
                // 默认处理：检查是否包含常见的文本类型关键词
                return lowerTypeName.contains("char") ||
                        lowerTypeName.contains("text") ||
                        lowerTypeName.contains("clob") ||
                        lowerTypeName.contains("xml");
        }
    }

    /**
     * 检查列名是否匹配模式
     */
    private static boolean matchesPattern(String colName, String pattern) {
        // 简单通配符匹配
        if (pattern.contains("%")) {
            String regex = pattern.replace("%", ".*").toLowerCase();
            return Pattern.matches(regex, colName.toLowerCase());
        }
        return colName.equalsIgnoreCase(pattern);
    }
}
